home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Programming / QuakeTools / src / libqbuild / brush.c next >
Encoding:
C/C++ Source or Header  |  1998-06-11  |  20.7 KB  |  926 lines

  1. #define    LIBQBUILD_CORE
  2. #include "../include/libqbuild.h"
  3.  
  4. //JIM
  5. struct entity *CurrentEntity;            // 4
  6.  
  7. vec3_t brush_mins, brush_maxs;            // 24
  8. struct visfacet *brush_faces;            // 4
  9.  
  10. vec3_t hull_size[3][2] =            // 72
  11. {
  12.   {
  13.     {0, 0, 0},
  14.     {0, 0, 0}},
  15.   {
  16.     {-16, -16, -32},
  17.     {16, 16, 24}},
  18.   {
  19.     {-32, -32, -64},
  20.     {32, 32, 24}}
  21. };
  22.  
  23. int num_hull_points;                // 4
  24. vec3_t hull_points[MAX_HULL_POINTS];        // 384
  25. vec3_t hull_corners[MAX_HULL_POINTS * 8];    // 3072
  26. int num_hull_edges;                // 4
  27. int hull_edges[MAX_HULL_EDGES][2];        // 512
  28.  
  29. //===========================================================================
  30.  
  31. /*
  32.  * =================
  33.  * CheckFace
  34.  * 
  35.  * Note: this will not catch 0 area polygons
  36.  * =================
  37.  */
  38. void CheckFace(__memBase, register struct visfacet * f)
  39. {
  40.   int i, j;
  41.   vec_t *p1, *p2;
  42.   vec_t d, edgedist;
  43.   vec3_t dir, edgenormal, facenormal;
  44.  
  45.   if (f->numpoints < 3)
  46.     Error("CheckFace: %i points", f->numpoints);
  47.  
  48. #ifdef EXHAUSIVE_CHECK
  49.   if(f->planenum >= bspMem->numbrushplanes || f->planenum < 0)
  50.     Error("looking for nonexisting plane %d\n", f->planenum);
  51. #endif
  52.   VectorCopy(bspMem->brushplanes[f->planenum].normal, facenormal);
  53.   if (f->planeside) {
  54.     VectorNegate(facenormal);
  55.   }
  56.  
  57.   for (i = 0; i < f->numpoints; i++) {
  58.     p1 = f->pts[i];
  59.  
  60.     for (j = 0; j < 3; j++)
  61.       if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
  62.     Error("CheckFace: BUGUS_RANGE: %g", p1[j]);
  63.  
  64.     j = i + 1 == f->numpoints ? 0 : i + 1;
  65.  
  66.     // check the point is on the face plane
  67.     d = DotProduct(p1, bspMem->brushplanes[f->planenum].normal) - bspMem->brushplanes[f->planenum].dist;
  68. //      if (d < -ON_EPSILON || d > ON_EPSILON)
  69.     //         Error ("CheckFace: point off plane");
  70.     //MED
  71.     if (d < -1 || d > 1)
  72.       Error("CheckFace: point off plane d=%f", d);
  73.  
  74.     // check the edge isn't degenerate
  75.     p2 = f->pts[j];
  76.     VectorSubtract(p2, p1, dir);
  77.  
  78.     if (VectorLength(dir) < ON_EPSILON)
  79.       Error("CheckFace: degenerate edge");
  80.  
  81.     CrossProduct(facenormal, dir, edgenormal);
  82.     VectorNormalize(edgenormal);
  83.     edgedist = DotProduct(p1, edgenormal);
  84.     edgedist += ON_EPSILON;
  85.  
  86.     // all other points must be on front side
  87. #ifndef    BETTER_BRANCH
  88.     for (j = 0; j < f->numpoints; j++) {
  89.       if (j == i)
  90.     continue;
  91.       d = DotProduct(f->pts[j], edgenormal);
  92.       if (d > edgedist)
  93.     Error("CheckFace: non-convex");
  94.     }
  95. #else
  96.     for (j = 0; j < i; j++)
  97.       if (DotProduct(f->pts[j], edgenormal) > edgedist)
  98.     Error("CheckFace: non-convex");
  99.     for (j++; j < f->numpoints; j++)
  100.       if (DotProduct(f->pts[j], edgenormal) > edgedist)
  101.     Error("CheckFace: non-convex");
  102. #endif
  103.   }
  104. }
  105.  
  106. //===========================================================================
  107.  
  108. /*
  109.  * =================
  110.  * ClearBounds
  111.  * =================
  112.  */
  113. void ClearBounds(register struct brushset * bs)
  114. {
  115.   short int i, j;
  116.  
  117.   //for (j = 0; j < NUM_HULLS; j++) {
  118. #ifndef    BETTER_BRANCH
  119.     for (i = 0; i < 3; i++) {
  120.       bs->mins[i] = 99999;
  121.       bs->maxs[i] = -99999;
  122.     }
  123. #else
  124.     bs->mins[0] = 99999;
  125.     bs->mins[1] = 99999;
  126.     bs->mins[2] = 99999;
  127.     bs->maxs[0] = -99999;
  128.     bs->maxs[1] = -99999;
  129.     bs->maxs[2] = -99999;
  130. #endif
  131.   //}
  132. }
  133.  
  134. /*
  135.  * =================
  136.  * AddToBounds
  137.  * =================
  138.  */
  139. void AddToBounds(register struct brushset * bs, register vec3_t v)
  140. {
  141.   short int i;
  142.  
  143.   for (i = 0; i < 3; i++) {
  144.     if (v[i] < bs->mins[i])
  145.       bs->mins[i] = v[i];
  146.     else if (v[i] > bs->maxs[i])
  147.       bs->maxs[i] = v[i];
  148.   }
  149. }
  150.  
  151. //===========================================================================
  152.  
  153. int PlaneTypeForNormal(vec3_t normal)
  154. {
  155.   float ax, ay, az;
  156.  
  157. // NOTE: should these have an epsilon around 1.0?
  158.   if (normal[0] == 1.0)
  159.     return PLANE_X;
  160.   if (normal[1] == 1.0)
  161.     return PLANE_Y;
  162.   if (normal[2] == 1.0)
  163.     return PLANE_Z;
  164.   if (normal[0] == -1.0 ||
  165.       normal[1] == -1.0 ||
  166.       normal[2] == -1.0)
  167.     Error("PlaneTypeForNormal: not a canonical vector");
  168.  
  169.   ax = fabs(normal[0]);
  170.   ay = fabs(normal[1]);
  171.   az = fabs(normal[2]);
  172.  
  173.   if (ax >= ay && ax >= az)
  174.     return PLANE_ANYX;
  175.   if (ay >= ax && ay >= az)
  176.     return PLANE_ANYY;
  177.   return PLANE_ANYZ;
  178. }
  179.  
  180. void NormalizePlane(register struct plane * dp)
  181. {
  182.   vec_t ax, ay, az;
  183.  
  184.   if (dp->normal[0] == -1.0) {
  185.     dp->normal[0] = 1.0;
  186.     dp->dist = -dp->dist;
  187.   }
  188.   if (dp->normal[1] == -1.0) {
  189.     dp->normal[1] = 1.0;
  190.     dp->dist = -dp->dist;
  191.   }
  192.   if (dp->normal[2] == -1.0) {
  193.     dp->normal[2] = 1.0;
  194.     dp->dist = -dp->dist;
  195.   }
  196.  
  197.   if (dp->normal[0] == 1.0) {
  198.     dp->type = PLANE_X;
  199.     return;
  200.   }
  201.   if (dp->normal[1] == 1.0) {
  202.     dp->type = PLANE_Y;
  203.     return;
  204.   }
  205.   if (dp->normal[2] == 1.0) {
  206.     dp->type = PLANE_Z;
  207.     return;
  208.   }
  209.  
  210.   ax = fabs(dp->normal[0]);
  211.   ay = fabs(dp->normal[1]);
  212.   az = fabs(dp->normal[2]);
  213.  
  214.   if (ax >= ay && ax >= az)
  215.     dp->type = PLANE_ANYX;
  216.   else if (ay >= ax && ay >= az)
  217.     dp->type = PLANE_ANYY;
  218.   else
  219.     dp->type = PLANE_ANYZ;
  220.   if (dp->normal[dp->type - PLANE_ANYX] < 0) {
  221.     VectorNegate(dp->normal);
  222.     dp->dist = -dp->dist;
  223.   }
  224.  
  225. }
  226.  
  227. /*
  228.  * ===============
  229.  * FindPlane
  230.  * 
  231.  * Returns a global plane number and the side that will be the front
  232.  * ===============
  233.  */
  234. int FindPlane(__memBase, register struct plane *dplane, register int *side)
  235. {
  236.   int i;
  237.   struct plane *dp, pl;
  238.   vec_t dot;
  239.  
  240.   dot = VectorLength(dplane->normal);
  241.   if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON)
  242.     Error("FindPlane: normalization error");
  243.  
  244.   pl = *dplane;
  245.   NormalizePlane(&pl);
  246.   if (DotProduct(pl.normal, dplane->normal) > 0)
  247.     *side = 0;
  248.   else
  249.     *side = 1;
  250.  
  251.   dp = bspMem->brushplanes;
  252.   for (i = 0; i < bspMem->numbrushplanes; i++, dp++) {
  253.     dot = DotProduct(dp->normal, pl.normal);
  254.     if (dot > 1.0 - ANGLEEPSILON
  255.     && fabs(dp->dist - pl.dist) < DISTEPSILON) {                   // regular match
  256.       return i;
  257.     }
  258.   }
  259.  
  260.   if (bspMem->numbrushplanes == bspMem->max_numbrushplanes)
  261.     ExpandClusters(bspMem, MAP_BRUSHPLANES);
  262.   bspMem->brushplanes[bspMem->numbrushplanes] = pl;
  263.   bspMem->numbrushplanes++;
  264.  
  265.   return bspMem->numbrushplanes - 1;
  266. }
  267.  
  268. /*
  269.  * ===============
  270.  * FindPlane_old
  271.  * 
  272.  * Returns a global plane number and the side that will be the front
  273.  * ===============
  274.  */
  275. int FindPlane_old(__memBase, register struct plane * dplane, register int *side)
  276. {
  277.   int i;
  278.   struct plane *dp;
  279.   vec_t dot, ax, ay, az;
  280.  
  281.   dot = VectorLength(dplane->normal);
  282.   if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON)
  283.     Error("FindPlane: normalization error");
  284.  
  285.   dp = bspMem->brushplanes;
  286.  
  287.   for (i = 0; i < bspMem->numbrushplanes; i++, dp++) {
  288.     dot = DotProduct(dplane->normal, dp->normal);
  289.     if (dot > 1.0 - ANGLEEPSILON
  290.     && fabs(dplane->dist - dp->dist) < DISTEPSILON) {               // regular match
  291.  
  292.       *side = 0;
  293.       return i;
  294.     }
  295.     if (dot < -1.0 + ANGLEEPSILON
  296.     && fabs(dplane->dist + dp->dist) < DISTEPSILON) {               // inverse of vector
  297.  
  298.       *side = 1;
  299.       return i;
  300.     }
  301.   }
  302.  
  303. // allocate a new plane, flipping normal to a consistant direction
  304.   // if needed
  305.   *dp = *dplane;
  306.  
  307.   if (bspMem->numbrushplanes == bspMem->max_numbrushplanes)
  308.     ExpandClusters(bspMem, MAP_BRUSHPLANES);
  309.   bspMem->numbrushplanes++;
  310.  
  311.   *side = 0;
  312.  
  313. // NOTE: should these have an epsilon around 1.0?
  314.   if (dplane->normal[0] == 1.0)
  315.     dp->type = PLANE_X;
  316.   else if (dplane->normal[1] == 1.0)
  317.     dp->type = PLANE_Y;
  318.   else if (dplane->normal[2] == 1.0)
  319.     dp->type = PLANE_Z;
  320.   else if (dplane->normal[0] == -1.0) {
  321.     dp->type = PLANE_X;
  322.     dp->normal[0] = 1.0;
  323.     dp->dist = -dp->dist;
  324.     *side = 1;
  325.   }
  326.   else if (dplane->normal[1] == -1.0) {
  327.     dp->type = PLANE_Y;
  328.     dp->normal[1] = 1.0;
  329.     dp->dist = -dp->dist;
  330.     *side = 1;
  331.   }
  332.   else if (dplane->normal[2] == -1.0) {
  333.     dp->type = PLANE_Z;
  334.     dp->normal[2] = 1.0;
  335.     dp->dist = -dp->dist;
  336.     *side = 1;
  337.   }
  338.   else {
  339.     ax = fabs(dplane->normal[0]);
  340.     ay = fabs(dplane->normal[1]);
  341.     az = fabs(dplane->normal[2]);
  342.  
  343.     if (ax >= ay && ax >= az)
  344.       dp->type = PLANE_ANYX;
  345.     else if (ay >= ax && ay >= az)
  346.       dp->type = PLANE_ANYY;
  347.     else
  348.       dp->type = PLANE_ANYZ;
  349.     if (dplane->normal[dp->type - PLANE_ANYX] < 0) {
  350.       VectorNegate(dp->normal);
  351.       dp->dist = -dp->dist;
  352.       *side = 1;
  353.     }
  354.   }
  355.  
  356.   return i;
  357. }
  358.  
  359. /*
  360.  * =============================================================================
  361.  * 
  362.  * TURN BRUSHES INTO GROUPS OF FACES
  363.  * 
  364.  * =============================================================================
  365.  */
  366.  
  367. /*
  368.  * =================
  369.  * CreateBrushFaces
  370.  * =================
  371.  */
  372. void CreateBrushFaces(__memBase)
  373. {
  374.   int i, j;
  375.   short int k;
  376.   vec_t r;
  377.   struct visfacet *f;
  378.   struct winding *w;
  379.   struct plane plane;
  380.   struct mface *mf;
  381.  
  382. //JIM
  383.   vec3_t offset;
  384.   vec3_t point;
  385.   vec_t max;
  386.   vec_t min;
  387.  
  388.   //JIM
  389.   offset[0] = offset[1] = offset[2] = 0;
  390.   brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999;
  391.   brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999;
  392.  
  393.   brush_faces = NULL;
  394.  
  395.   //JIM
  396.   if (!strncmp(CurrentEntity->classname, "rotate_", 7)) {
  397.     char text[32];
  398.     if (CurrentEntity->targetent) {
  399.       GetVectorForKey(CurrentEntity->targetent, "origin", offset);
  400.       sprintf(text, "%g %g %g", offset[0], offset[1], offset[2]);
  401.       SetKeyValue(CurrentEntity, "origin", text);
  402.     }
  403.   }
  404.  
  405.   for (i = 0; i < bspMem->numbrushfaces; i++) {
  406.     mf = &bspMem->brushfaces[i];
  407.  
  408.     w = BaseWindingForPlane(&mf->plane);
  409.     /*
  410.      * if (!w)
  411.      *   printf("basewinding failed\n");
  412.      */
  413.  
  414.     for (j = 0; j < bspMem->numbrushfaces && w; j++) {
  415.       if (j == i)
  416.     continue;
  417.       // flip the plane, because we want to keep the back side
  418.       VectorNegateTo(bspMem->brushfaces[j].plane.normal, plane.normal);
  419.       plane.dist = -bspMem->brushfaces[j].plane.dist;
  420.  
  421.       w = ClipWinding(w, &plane, FALSE);
  422.       /*
  423.        * if (!w)
  424.        *   printf("clipwinding failed\n");
  425.        */
  426.     }
  427.  
  428.     if (!w) {
  429.       /*
  430.        * printf("overcontrained plane\n");
  431.        */
  432.       continue;                                       // overcontrained plane
  433.     }
  434.  
  435.     // this face is a keeper
  436.     f = AllocFace(w->numpoints);
  437.     f->numpoints = w->numpoints;
  438.     if (f->numpoints > MAXEDGES)
  439.       Error("f->numpoints > MAXEDGES");
  440.  
  441.     // mprintf("CreateBrushFaces: make face with %d points\n", f->numpoints);
  442.  
  443.     for (j = 0; j < w->numpoints; j++) {
  444.       for (k = 0; k < 3; k++) {
  445.     //JIM
  446.     point[k] = w->points[j][k] - offset[k];
  447.     r = rint(point[k]);
  448.     if (fabs(point[k] - r) < ZERO_EPSILON)
  449.       f->pts[j][k] = r;
  450.     else
  451.       f->pts[j][k] = point[k];
  452.  
  453.     if (f->pts[j][k] < brush_mins[k])
  454.       brush_mins[k] = f->pts[j][k];
  455.     if (f->pts[j][k] > brush_maxs[k])
  456.       brush_maxs[k] = f->pts[j][k];
  457.     if (f->pts[j][k] < min)
  458.       min = f->pts[j][k];
  459.     if (f->pts[j][k] > max)
  460.       max = f->pts[j][k];
  461.       }
  462.  
  463.     }
  464.     //JIM
  465.     VectorCopy(mf->plane.normal, plane.normal);
  466.     VectorScale(mf->plane.normal, mf->plane.dist, point);
  467.     VectorSubtract(point, offset, point);
  468.     plane.dist = DotProduct(plane.normal, point);
  469.  
  470.     FreeWinding(w);
  471.     f->texturenum = mf->texinfo;
  472.     //JIM
  473.     f->planenum = FindPlane(bspMem, &plane, &f->planeside);
  474. //      f->planenum = FindPlane (&mf->plane, &f->planeside);
  475.     f->next = brush_faces;
  476.     brush_faces = f;
  477.     CheckFace(bspMem, f);
  478.   }
  479.  
  480.   // Rotatable objects have to have a bounding box big enough
  481.   // to account for all its rotations.
  482.   if (!strncmp(CurrentEntity->classname, "rotate_", 7)) {
  483.     vec_t delta;
  484.  
  485.     delta = fabs(max);
  486.     if (fabs(min) > delta)
  487.       delta = fabs(min);
  488.  
  489.     for (k = 0; k < 3; k++) {
  490.       brush_mins[k] = -delta;
  491.       brush_maxs[k] = delta;
  492.     }
  493.   }
  494. }
  495.  
  496. /*
  497.  * ==============================================================================
  498.  * 
  499.  * BEVELED CLIPPING HULL GENERATION
  500.  * 
  501.  * This is done by brute force, and could easily get a lot faster if anyone cares.
  502.  * ==============================================================================
  503.  */
  504.  
  505. /*
  506.  * ============
  507.  * AddBrushPlane
  508.  * =============
  509.  */
  510. void AddBrushPlane(__memBase, register struct plane * plane)
  511. {
  512.   int i;
  513.   struct plane *pl;
  514.   float l;
  515.  
  516.   if (bspMem->numbrushfaces == bspMem->max_numbrushfaces)
  517.     ExpandClusters(bspMem, MAP_BRUSHFACES);
  518.  
  519.   l = VectorLength(plane->normal);
  520.   if (l < 0.999 || l > 1.001)
  521.     Error("AddBrushPlane: bad normal");
  522.  
  523.   for (i = 0; i < bspMem->numbrushfaces; i++) {
  524.     pl = &bspMem->brushfaces[i].plane;
  525.     if (VectorCompare(pl->normal, plane->normal)
  526.     && fabs(pl->dist - plane->dist) < ON_EPSILON)
  527.       return;
  528.   }
  529.   bspMem->brushfaces[i].plane = *plane;
  530.   bspMem->brushfaces[i].texinfo = bspMem->brushfaces[0].texinfo;
  531.   bspMem->numbrushfaces++;
  532. }
  533.  
  534. /*
  535.  * ============
  536.  * TestAddPlane
  537.  * 
  538.  * Adds the given plane to the brush description if all of the original brush
  539.  * vertexes can be put on the front side
  540.  * =============
  541.  */
  542. void TestAddPlane(__memBase, register struct plane * plane)
  543. {
  544.   int i, c;
  545.   vec_t d;
  546.   vec_t *corner;
  547.   struct plane flip;
  548.   vec3_t inv;
  549.   int counts[3];
  550.   struct plane *pl;
  551.  
  552. // see if the plane has allready been added
  553.   for (i = 0; i < bspMem->numbrushfaces; i++) {
  554.     pl = &bspMem->brushfaces[i].plane;
  555.     if (VectorCompare(plane->normal, pl->normal) && fabs(plane->dist - pl->dist) < ON_EPSILON)
  556.       return;
  557.     VectorNegateTo(plane->normal, inv);
  558.     if (VectorCompare(inv, pl->normal) && fabs(plane->dist + pl->dist) < ON_EPSILON)
  559.       return;
  560.   }
  561.  
  562. // check all the corner points
  563.   counts[0] = counts[1] = counts[2] = 0;
  564.   c = num_hull_points * 8;
  565.  
  566.   corner = hull_corners[0];
  567.   for (i = 0; i < c; i++, corner += 3) {
  568.     d = DotProduct(corner, plane->normal) - plane->dist;
  569.     if (d < -ON_EPSILON) {
  570.       if (counts[0])
  571.     return;
  572.       counts[1]++;
  573.     }
  574.     else if (d > ON_EPSILON) {
  575.       if (counts[1])
  576.     return;
  577.       counts[0]++;
  578.     }
  579.     else
  580.       counts[2]++;
  581.   }
  582.  
  583. // the plane is a seperator
  584.  
  585.   if (counts[0]) {
  586.     VectorNegateTo(plane->normal, flip.normal);
  587.     flip.dist = -plane->dist;
  588.     plane = &flip;
  589.   }
  590.  
  591.   AddBrushPlane(bspMem, plane);
  592. }
  593.  
  594. /*
  595.  * ============
  596.  * AddHullPoint
  597.  * 
  598.  * Doesn't add if duplicated
  599.  * =============
  600.  */
  601. int AddHullPoint(register vec3_t p, register int hullnum)
  602. {
  603.   int i;
  604.   vec_t *c;
  605.   short int x, y, z;
  606.  
  607.   for (i = 0; i < num_hull_points; i++)
  608.     if (VectorCompare(p, hull_points[i]))
  609.       return i;
  610.  
  611.   VectorCopy(p, hull_points[num_hull_points]);
  612.  
  613.   c = hull_corners[i * 8];
  614.  
  615.   for (x = 0; x < 2; x++)
  616.     for (y = 0; y < 2; y++)
  617.       for (z = 0; z < 2; z++) {
  618.     c[0] = p[0] + hull_size[hullnum][x][0];
  619.     c[1] = p[1] + hull_size[hullnum][y][1];
  620.     c[2] = p[2] + hull_size[hullnum][z][2];
  621.     c += 3;
  622.       }
  623.  
  624.   if (num_hull_points == MAX_HULL_POINTS)
  625.     Error("MAX_HULL_POINTS");
  626.  
  627.   num_hull_points++;
  628.  
  629.   return i;
  630. }
  631.  
  632. /*
  633.  * ============
  634.  * AddHullEdge
  635.  * 
  636.  * Creates all of the hull planes around the given edge, if not done allready
  637.  * =============
  638.  */
  639. void AddHullEdge(__memBase, register vec3_t p1, register vec3_t p2, register int hullnum)
  640. {
  641.   int pt1, pt2;
  642.   int i;
  643.   short int a, b, c, d, e;
  644.   vec3_t edgevec, planeorg, planevec;
  645.   struct plane plane;
  646.   vec_t l;
  647.  
  648.   pt1 = AddHullPoint(p1, hullnum);
  649.   pt2 = AddHullPoint(p2, hullnum);
  650.  
  651.   for (i = 0; i < num_hull_edges; i++)
  652.     if ((hull_edges[i][0] == pt1 && hull_edges[i][1] == pt2)
  653.     || (hull_edges[i][0] == pt2 && hull_edges[i][1] == pt1))
  654.       return;                                       // allread added
  655.  
  656.   if (num_hull_edges == MAX_HULL_EDGES)
  657.     Error("MAX_HULL_EDGES");
  658.  
  659.   hull_edges[i][0] = pt1;
  660.   hull_edges[i][1] = pt2;
  661.   num_hull_edges++;
  662.  
  663.   VectorSubtract(p1, p2, edgevec);
  664.   VectorNormalize(edgevec);
  665.  
  666.   for (a = 0; a < 3; a++) {
  667.     b = (a + 1) % 3;
  668.     c = (a + 2) % 3;
  669.     for (d = 0; d <= 1; d++)
  670.       for (e = 0; e <= 1; e++) {
  671.     VectorCopy(p1, planeorg);
  672.     planeorg[b] += hull_size[hullnum][d][b];
  673.     planeorg[c] += hull_size[hullnum][e][c];
  674.  
  675.     VectorClear(planevec);
  676.     planevec[a] = 1;
  677.  
  678.     CrossProduct(planevec, edgevec, plane.normal);
  679.     l = VectorLength(plane.normal);
  680.     if (l < 1 - ANGLEEPSILON || l > 1 + ANGLEEPSILON)
  681.       continue;
  682.     plane.dist = DotProduct(planeorg, plane.normal);
  683.     TestAddPlane(bspMem, &plane);
  684.       }
  685.   }
  686.  
  687. }
  688.  
  689. /*
  690.  * ============
  691.  * ExpandBrush
  692.  * =============
  693.  */
  694. void ExpandBrush(__memBase, register int hullnum)
  695. {
  696.   int i, s;
  697.   short int x;
  698.   vec3_t corner;
  699.   struct visfacet *f;
  700.   struct plane plane, *p;
  701.  
  702.   num_hull_points = 0;
  703.   num_hull_edges = 0;
  704.  
  705. // create all the hull points
  706.   for (f = brush_faces; f; f = f->next)
  707.     for (i = 0; i < f->numpoints; i++)
  708.       AddHullPoint(f->pts[i], hullnum);
  709.  
  710. // expand all of the planes
  711.   for (i = 0; i < bspMem->numbrushfaces; i++) {
  712.     p = &bspMem->brushfaces[i].plane;
  713.     VectorClear(corner);
  714.     for (x = 0; x < 3; x++) {
  715.       if (p->normal[x] > 0)
  716.     corner[x] = hull_size[hullnum][1][x];
  717.       else if (p->normal[x] < 0)
  718.     corner[x] = hull_size[hullnum][0][x];
  719.     }
  720.     p->dist += DotProduct(corner, p->normal);
  721.   }
  722.  
  723. // add any axis planes not contained in the brush to bevel off corners
  724.   for (x = 0; x < 3; x++)
  725.     for (s = -1; s <= 1; s += 2) {
  726.       // add the plane
  727.       VectorClear(plane.normal);
  728.       plane.normal[x] = s;
  729.       if (s == -1)
  730.     plane.dist = -brush_mins[x] + -hull_size[hullnum][0][x];
  731.       else
  732.     plane.dist = brush_maxs[x] + hull_size[hullnum][1][x];
  733.       AddBrushPlane(bspMem, &plane);
  734.     }
  735.  
  736. // add all of the edge bevels
  737.   for (f = brush_faces; f; f = f->next)
  738.     for (i = 0; i < f->numpoints; i++)
  739.       AddHullEdge(bspMem, f->pts[i], f->pts[(i + 1) % f->numpoints], hullnum);
  740. }
  741.  
  742. //============================================================================
  743.  
  744. /*
  745.  * ===============
  746.  * LoadBrush
  747.  * 
  748.  * Converts a mapbrush to a bsp brush
  749.  * ===============
  750.  */
  751. struct brush *LoadBrush(__memBase, register struct mbrush * mb, register int hullnum)
  752. {
  753.   struct brush *b;
  754.   int contents;
  755.   char *name;
  756.   struct mface *f;
  757.  
  758. //
  759.   // check texture name for attributes
  760.   //
  761.   name = bspMem->maptexstrings[bspMem->texinfo[mb->faces->texinfo].miptex];
  762.  
  763.   if (!strcasecmp(name, "clip") && hullnum == 0) {
  764.     return NULL;                                   // "clip" brushes don't show up in the draw hull
  765.   }
  766.  
  767.   if (name[0] == '*' && worldmodel)                           // bspMem->mapentities never use water merging
  768.    {
  769.     if (!strncasecmp(name + 1, "lava", 4))
  770.       contents = CONTENTS_LAVA;
  771.     else if (!strncasecmp(name + 1, "slime", 5))
  772.       contents = CONTENTS_SLIME;
  773.     else
  774.       contents = CONTENTS_WATER;
  775.   }
  776.   else if (!strncasecmp(name, "sky", 3) && worldmodel && hullnum == 0)
  777.     contents = CONTENTS_SKY;
  778.   else
  779.     contents = CONTENTS_SOLID;
  780.  
  781.   if (hullnum && contents != CONTENTS_SOLID && contents != CONTENTS_SKY) {
  782.     return NULL;                                   // water brushes don't show up in clipping hulls
  783.   }
  784.  
  785. // no seperate textures on clip hull
  786.  
  787. //
  788.   // create the faces
  789.   //
  790.   brush_faces = NULL;
  791.  
  792.   bspMem->numbrushfaces = 0;
  793.   for (f = mb->faces; f; f = f->next) {
  794.     bspMem->brushfaces[bspMem->numbrushfaces] = *f;
  795.     if (hullnum)
  796.       bspMem->brushfaces[bspMem->numbrushfaces].texinfo = 0;
  797.     bspMem->numbrushfaces++;
  798.   }
  799.  
  800.   CreateBrushFaces(bspMem);
  801.  
  802.   if (!brush_faces) {
  803.     eprintf("couldn't create brush faces\n");
  804.     return NULL;
  805.   }
  806.  
  807.   if (hullnum) {
  808.     ExpandBrush(bspMem, hullnum);
  809.     CreateBrushFaces(bspMem);
  810.   }
  811.  
  812. //
  813.   // create the brush
  814.   //
  815.   b = AllocBrush();
  816.  
  817.   b->contents = contents;
  818.   b->faces = brush_faces;
  819.   VectorCopy(brush_mins, b->mins);
  820.   VectorCopy(brush_maxs, b->maxs);
  821.  
  822.   return b;
  823. }
  824.  
  825. //=============================================================================
  826.  
  827. /*
  828.  * ============
  829.  * Brush_DrawAll
  830.  * 
  831.  * ============
  832.  */
  833. void Brush_DrawAll(register struct brushset * bs)
  834. {
  835.   struct brush *b;
  836.   struct visfacet *f;
  837.  
  838.   for (b = bs->brushes; b; b = b->next)
  839.     for (f = b->faces; f; f = f->next)
  840.       Draw_DrawFace(f);
  841. }
  842.  
  843. #if 0
  844. /*
  845.  * added by Niels
  846.  */
  847. struct mbrush *FreeBrush(register struct mbrush *mbr) {
  848.   struct mbrush *mn = mbr->next;
  849.   struct mface *mf = mbr->faces;
  850.   tfree(mbr);
  851.   while(mf) {
  852.     struct mface *mfn = mf->next;
  853.     tfree(mf);
  854.     mf = mfn;
  855.   }
  856.   return mn;
  857. }
  858. #endif
  859.  
  860. /*
  861.  * ============
  862.  * Brush_LoadEntity
  863.  * ============
  864.  */
  865. struct brushset *Brush_LoadEntity(__memBase, struct entity * ent, int hullnum)
  866. {
  867.   struct brush *b, *next, *water, *other;
  868.   struct mbrush *mbr;
  869.   int numbrushes, numbrushesp, i;
  870.   struct brushset *bset;
  871.  
  872.   if(!(bset = (struct brushset *)tmalloc(sizeof(struct brushset))))
  873.     Error("BrushLoadEntity: failed to allocate brushset!\n");
  874.   
  875.   ClearBounds(bset);
  876.  
  877.   numbrushes = 0;
  878.   numbrushesp = 0;
  879.   other = water = NULL;
  880.  
  881.   mprintf("----- BrushLoadEntity ---\n");
  882.  
  883.   CurrentEntity = ent;
  884.  
  885.   /* added by niels "mbr = FreeBrush(mbr)" */
  886.   for (mbr = ent->brushes; mbr; mbr = mbr->next)
  887.     numbrushesp++;
  888.  
  889.   for (mbr = ent->brushes, i = 0; mbr; mbr = mbr->next, i++) {
  890.     if((b = LoadBrush(bspMem, mbr, hullnum))) {
  891.       numbrushes++;
  892.  
  893.       if (b->contents != CONTENTS_SOLID) {
  894.         b->next = water;
  895.         water = b;
  896.       }
  897.       else {
  898.         b->next = other;
  899.         other = b;
  900.       }
  901.  
  902.       AddToBounds(bset, b->mins);
  903.       AddToBounds(bset, b->maxs);
  904.     }
  905.     mprogress(numbrushesp, i + 1);
  906.   }
  907.  
  908. // add all of the water textures at the start
  909.   for (b = water; b; b = next) {
  910.     next = b->next;
  911.     b->next = other;
  912.     other = b;
  913.   }
  914.  
  915.   bset->brushes = other;
  916.   /* PROGRESS-ONLY! */
  917.   bset->numbrushes = numbrushes;
  918.  
  919.   brushset = bset;
  920.   Brush_DrawAll(bset);
  921.  
  922.   mprintf("%5i brushes read\n", numbrushes);
  923.  
  924.   return bset;
  925. }
  926.